/*
 * $RCSfile: DbConnection.java,v $
 * $Revision: 1.34 $
 *
 * Comments:
 *
 * (C) Copyright Biuro-Technika 2004.  All rights reserved.
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Biuro-Technika
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 *
 * $Author: michal $          $Locker:  $
 * $Date: 2010/06/01 09:06:03 $
 * $Log: DbConnection.java,v $
 * Revision 1.34  2010/06/01 09:06:03  michal
 * dodanie funkcji varcharCast z dowolnym formatem
 *
 * Revision 1.33  2010/04/26 11:12:29  michal
 * dodanie pol current_timestamp oraz current_date
 *
 * Revision 1.32  2010/04/13 09:29:44  michal
 * parametryzacja kodu
 *
 * Revision 1.31  2010/03/03 10:31:41  michal
 * zmiana dostepnosci pol
 *
 * Revision 1.30  2010/02/25 14:20:41  michal
 * dodanie dateCast oraz timestampCast
 *
 * Revision 1.29  2010/02/25 10:34:15  mdettla
 * Poprawienie metody datetimeExtract.
 *
 * Revision 1.28  2010/02/24 14:32:39  mdettla
 * Dodanie metody datetimeExtract.
 *
 * Revision 1.27  2010/02/16 15:13:35  michal
 * zmiana widocznosci metody correct
 *
 * Revision 1.26  2010/01/29 14:32:03  michal
 * uporzadkowanie kodu
 *
 * Revision 1.25  2009/09/22 11:46:35  michal
 * ParaSoft -> Biuro-Technika
 *
 * Revision 1.24  2009/09/16 09:36:07  michal
 * dodanie obslugi zapamietywania ostatniego zapytania
 *
 * Revision 1.23  2009/05/25 07:59:37  michal
 * dodanie metody alterColumnType
 *
 * Revision 1.22  2009/05/15 06:55:51  michal
 * dodnaie metody getFullTableColumn
 *
 * Revision 1.21  2009/04/20 07:35:36  michal
 * dodanie komentarzy do metod abstrakcyjnych
 *
 * Revision 1.20  2009/02/10 06:45:26  michal
 * zmiana dostepnosci metody getConnection
 *
 * Revision 1.19  2009/01/02 13:32:04  michal
 * zmiana statycznej nazwy schemy centralnej na dynamiczna
 *
 * Revision 1.18  2008/12/09 08:22:23  michal
 * dodanie metod dropColumn oraz sTempSelect
 *
 * Revision 1.17  2008/06/13 11:18:21  michal
 * zwracanie DatabaseMetaData
 *
 * Revision 1.16  2007/12/06 10:27:14  rudi
 * Zmiana funkcji prepareScrollableStatement
 *
 * Revision 1.15  2007/11/13 12:30:38  muzzy
 * nowa existsFunction
 *
 * Revision 1.14  2007/10/25 14:37:32  muzzy
 * poprawki w indexach, round i numericCast
 *
 * Revision 1.13  2007/08/24 09:03:10  dominik
 * Dodanie nowych metod abstrakcyjnych
 *
 * Revision 1.12  2007/03/09 10:55:45  dominik
 * Dodanie opcji SERWIS_DEBUG_SELECT umozliwiajacej wpisywanie selectow do schemy serwis
 *
 * Revision 1.11  2007/02/06 14:03:42  dominik
 * Zmiana zmiennej user na nie-statyczna
 *
 * Revision 1.10  2007/02/05 13:22:44  dominik
 * Dodanie metody getUserLogin()
 *
 * Revision 1.9  2007/01/16 15:50:13  dominik
 * Zamiana PreparedStatement na DebuggablePreparedStatement - debugowanie zapytania
 *
 * Revision 1.8  2006/01/31 15:39:12  muzzy
 * sprawdzanie istnienia funkcji
 *
 * Revision 1.7  2005/10/13 14:15:29  muzzy
 * triggery, funkcje i left join
 *
 * Revision 1.6  2005/04/14 13:35:51  limbur
 * Optymalizacja importow...
 *
 * Revision 1.5  2005/01/18 15:00:52  limbur
 * Dodano funkcje bitand(...)
 *
 * Revision 1.4  2005/01/05 17:57:07  limbur
 * Uwzgledniono kolejne roznice pomiedzy Oracle - PostgreSQL
 *
 * Revision 1.3  2004/12/20 13:21:08  limbur
 * Dodano funkcje createScrolloableStatemet, prepareScrolloableStatemet
 *
 * Revision 1.2  2004/12/17 17:11:20  limbur
 * PostgreSQL - kolejne zmiany
 *
 * Revision 1.1  2004/12/15 08:42:47  limbur
 * Przepakietowanie. Wersja pod PostgreSQL.
 *
 */

package parasoft.centrap.connection;

import static parasoft.centrap.utils.Error.no_broker;
import static parasoft.centrap.utils.Error.no_more_connections;

import java.io.PrintStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import parasoft.centrap.migration.Column;
import parasoft.centrap.migration.Index;
import parasoft.centrap.utils.Container;

/**
 *	Klasa tworz�ca trzon dla po��cze� 
 *	@see parasoft.centrap.connection.PostgreSQLConnection
 *	@see parasoft.centrap.connection.OracleConnection
 */
public abstract class DbConnection
{
    /** Wyj�cie dla wykonywanych zapyta� */
	protected PrintStream debug = null;
    /** Broker tego po��czenia */
    protected DbConnectionBroker broker;
    /** Po��czenie z baz� */
    protected Connection connection;
    /** Obiektu deklaracji zapyta� */
    protected Vector<Statement> statements;
    /** czy logowa� zapytania */
    protected boolean logged = true;
    /** Nazwa u�ytkownika, kt�ry u�ywa tego po��czenia */
    protected String user = "";
    /** Nazwa schematu centralnego */
	protected static String mainSchema = "";
    /** Ostatnie zapytanie */
    protected static String LAST_QUERY;
    /** Ostatni czas startu zapytania */
    protected static long LAST_START_TIME;
    /** Ostatni czas zapytania */
    protected static long LAST_EXECUTION_TIME;
    /**  @since centrala-2_38*/
    protected Container values = new Container();

    /**
     * Konstruktor domy�lny
     */
    public DbConnection(){
    }
    /**
     * Konstruktor domy�lny
     * @param broker broker
     * @throws SQLException
     */
    public DbConnection(final DbConnectionBroker broker) throws SQLException
    {
    	this(broker, false);
    }
    /**
     * Konstruktor z podanego po��czenia
     * @param broker broker
     * @param conn conn
     * @throws SQLException
     */
    public DbConnection(final DbConnectionBroker broker, final Connection conn) throws SQLException
    {
        this.broker = broker;
        if (broker != null) {
        	connection = broker.getConnection(broker.idOfConnection(conn));
        }
        else {
            throw no_broker.sql();
        }
        if (connection == null) {
            throw no_more_connections.sql();
        }
        statements = new Vector<Statement>();
    }
    /**
     * Konstruktor z ostatnio u�ywanego po��czenia
     * @param broker broker
     * @param last last
     * @throws SQLException
	 * @since centrala-2_38
     */
    public DbConnection(final DbConnectionBroker broker, final boolean last) throws SQLException
    {
        this.broker = broker;
        if (broker != null) {
        	if(last){
        		connection = broker.getConnection(broker.getLastConnection());
        	}
        	if (connection == null){
        		connection = broker.getConnection();
        	}
        }
        else {
            throw no_broker.sql();
        }
        if (connection == null) {
            throw no_more_connections.sql();
        }
        statements = new Vector<Statement>();
    }

    /**
     * Ustawia strumie� wyj�ciowy dla b��d�w
     * @param stream stream
     */
    public void setDebug(final PrintStream stream)
    {
        debug = stream;
    }

    /**
     * Pobiera Connection
     * @return Connection
     */
    public Connection getConnection()
    {
        return connection;
    }

    /**
     * Pobiera DbConnectionBroker
     * @return DbConnectionBroker
     */
    protected DbConnectionBroker getConnectionBroker()
    {
        return broker;
    }

    /**
     * Zwraca nazw� u�ytkownika, kt�ry wykorzystuje to po��czenie
     * @return String
     */
    public String getUserLogin()
    {
        return user;
    }

    /**
     * Tworzy obiekt Statement z przewijalnym zbiorem wynik�w
     * @return Statement
     * @throws SQLException
     */
    public Statement createStatement() throws SQLException
    {
        final Statement stmt = connection.createStatement();
        statements.add(stmt);
        return stmt;
    }

    /**
     * Tworzy obiekt Statement
     * @return Statement
     * @throws SQLException
     */
    public Statement createScrollableStatemet() throws SQLException
    {
        final Statement stmt = connection.createStatement(
            ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        statements.add(stmt);
        return stmt;
    }

    /**
     * Tworzy obiekt DebuggablePreparedStatement
     * @param sql sql
     * @return DebuggablePreparedStatement
     * @throws SQLException
     */
    public DebuggablePreparedStatement prepareStatement(final String sql) throws SQLException
    {
        if (debug != null) {
            debug.println(sql);
        }
        final DebuggablePreparedStatement debugStmt = new DebuggablePreparedStatement(connection, sql, this);
        statements.add(debugStmt);
        return debugStmt;
    }

    /**
     * Tworzy obiekt DebuggablePreparedStatement z przewijalnym zbiorem wynik�w
     * @param sql sql
     * @return DebuggablePreparedStatement
     * @throws SQLException
     */
    public DebuggablePreparedStatement prepareScrollableStatement(final String sql) throws SQLException
    {
        if (debug != null) {
            debug.println(sql);
        }
        final DebuggablePreparedStatement debugStmt = new DebuggablePreparedStatement(connection, sql, this, true);
        statements.add(debugStmt);
        return debugStmt;
    }

    /**
     * Zamyka obiekt zapytania
     * @param stmt stmt
     */
    public void closeStatement(final Statement stmt)
    {
        if (stmt != null) {
            try {
            		stmt.close();
            	}
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
            statements.remove(stmt);
        }
    }

    /**
     * Zamyka obiekt zapytania
     * @param rs rs
     */
    public void closeStatement(final ResultSet rs)
    {
        if (rs != null) {
            try {
            		rs.close();
            	}
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
            try {
            		closeStatement(rs.getStatement());
            	}
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
        }
    }

    /**
     * Zamyka obiektu zapytania
     * @param rs rs
     * @param stmt stmt
     */
    public void closeStatement(final ResultSet rs, final Statement stmt)
    {
        if (rs != null) {
            if (stmt != null) {
                try {
                		rs.close();
                	}
                catch (final SQLException e) {
                    System.err.println(e.getMessage());
                }
            }
            else {
                closeStatement(rs);
                return;
            }

        }
        if (stmt != null) {
            try {
            		stmt.close();
            	}
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
            statements.remove(stmt);
        }
    }

    /**
     * Anuluje aktualnie trwaj�c� zapytania
     */
    public void closeAllStatements()
    {
        if (statements != null) {
            for (final Statement stmt : statements){
                try {
                    	if(stmt!=null){
                    		stmt.close();
                    	}
                    }
                catch (final SQLException e) {
                    System.err.println(e.getMessage());
                }
            }
            statements.removeAllElements();
        }
    }

    /**
     * Anuluje aktualnie trwaj�c� zapytanie
     * @param stmt stmt
     */
    public void cancelStatement(final Statement stmt)
    {
        if (stmt != null) {
            try {
                stmt.cancel();
            }
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
            statements.remove(stmt);
        }
    }

    /**
     * Anuluje aktualnie trwaj�ce zapytania
     */
    public void cancelAllStatements()
    {
        for (final Statement stmt : statements){
            try {
            	if (stmt != null) {
            		stmt.cancel();
            	}
            }
            catch (final SQLException e) {
                System.err.println(e.getMessage());
            }
        }
        statements.removeAllElements();
    }

    /**
     * Wykonuje zapytanie
     * @param sql
     * @return int
     * @throws SQLException
     */
    public int executeUpdate(final String sql) throws SQLException
    {
        if (debug != null) {
            debug.println(sql);
        }
        if (logged) {
            makeSerwisLog(sql, "EXECUTE_UPDATE");
        }
        final PreparedStatement stmt = connection.prepareStatement(sql);
        final int result = stmt.executeUpdate();
        stmt.close();
        return result;
    }

    /**
     * Wykonuje zapytanie
     * @param sql sql
     * @return ResultSet
     * @throws SQLException
     */
    public ResultSet executeQuery(final String sql) throws SQLException
    {
        if (debug != null) {
            debug.println(sql);
        }
        if (logged) {
            makeSerwisLog(sql, "EXECUTE_QUERY");
        }

        final PreparedStatement stmt = connection.prepareStatement(sql);
        statements.add(stmt);
        return stmt.executeQuery();
    }

    /**
     * Rozpoczyna now� tranzakcj�
     * @throws SQLException
     */
    public void startTransaction() throws SQLException
    {
        connection.setAutoCommit(false);
    }

    /**
     * Ko�czy aktualnie trwaj�c� tranzakcj�
     * @throws SQLException
     */
    public void finishTransaction() throws SQLException
    {
        try {
            connection.commit();
        }
        finally {
            connection.setAutoCommit(true);
        }
    }

    /**
     * Anuluje aktualnie trwaj�c� tranzakcj�
     * @throws SQLException
     */
    public void cancelTransaction() throws SQLException
    {
        try {
            connection.rollback();
        }
        finally {
            connection.setAutoCommit(true);
        }
    }

    /**
     * Zamyka po��czenie
     */
    public void close()
    {
        closeAllStatements();
        if (connection != null) {
            broker.freeConnection(connection);
            connection = null;
        }
    }

    /**
     * Anuluje aktualnie trwaj�ce po��czenie
     */
    public void cancel()
    {
        cancelAllStatements();
        if (connection != null) {
            broker.freeConnection(connection);
            connection = null;
        }
    }

    /**
     * Zamyka po��czenie
     */
    public void destroy()
    {
        close();
        statements = null;
    }

    /**
     * Ustawia warto�� lond w aktualnym zapytaniu
     * @param stmt stmt
     * @param index index
     * @param value value
     * @throws SQLException
     */
    public void setId(final DebuggablePreparedStatement stmt, final int index, final long value) throws SQLException
    {
        stmt.setLong(index, value);
    }

    /**
     * Tworzy nazw� indeksu z podanych parametr�w
     * @param schema schema
     * @param table table
     * @param column column
     * @return String
     */
    public String createIndexName(final String schema, final String table, final String column)
    {
        return schema + "_" + table + "_" + column;
    }

    /**
     * Zapisuje zapytanie do bazy danych
     * @param query query
     * @throws SQLException
     */
    public synchronized void makeSerwisLog(final String query) throws SQLException
    {
        makeSerwisLog(query, "");
    }

    /**
     * Zapisuje zapytanie do bazy danych
     * @param query query
     * @param rodzaj_query rodzaj_query
     * @throws SQLException
     */
    public synchronized void makeSerwisLog(final String query, final String rodzaj_query) throws SQLException
    {
        makeSerwisLog(query, rodzaj_query, null);
    }

    /**
     * Zapisuje zapytanie do bazy danych
     * @param query query
     * @param rodzaj_query rodzaj_query
     * @param czas_wykonania czas_wykonania
     * @throws SQLException
     */
    public synchronized void makeSerwisLog(final String query, final String rodzaj_query, final Double czas_wykonania) throws SQLException
    {
        final boolean bSelect = false;
		if ((!(query.toUpperCase().startsWith("SELECT") || query.toUpperCase()
				.startsWith("(SELECT")) || bSelect)) {
            setLogged(false);
            String queryLog ="INSERT INTO SERWIS.CHANGE_LOG(CHLOG_ID,USER_LOGIN,LOG_DATE,LOG_QUERY,";
            if (czas_wykonania != null) {
                queryLog += "TIME_EXECUTING,";
            }
            queryLog += "TYPE_QUERY) VALUES (?,?,?,?,";
            if (czas_wykonania != null) {
                queryLog += "?,";
            }
            queryLog += "?)";

            String user = "--"+mainSchema.toUpperCase()+"--";
            if (this.user != "") {
                user = this.user;
            }

            final PreparedStatement stmt = connection.prepareStatement(queryLog);
            int param_nr = 1;
            stmt.setLong(param_nr++, nextId("SERWIS.CHLOG_ID"));
            stmt.setString(param_nr++, user);
            stmt.setTimestamp(param_nr++, new java.sql.Timestamp(System.currentTimeMillis()));
            stmt.setString(param_nr++, query);
            if (czas_wykonania != null) {
                stmt.setDouble(param_nr++, czas_wykonania.doubleValue() / 1000);
            }
            stmt.setString(param_nr++, rodzaj_query);

            stmt.execute();
            stmt.close();
            setLogged(true);
        }
    }

    /**
     * Ustawia czy debugowa� zapytania
     * @param logged logged
     */
    public void setLogged(final boolean logged)
    {
        this.logged = logged;
    }

    /**
     * Ustawia u�ytkownika, kt�ry wykorzystuje to po��czenie
     * @param user user
     */
    public void setUser(final String user)
    {
        this.user = user;
    }

    /**
     * Pobiera kolumny z tabeli
     * @param schema schema
     * @param table table
     * @return List<Column>
     * @throws SQLException
     */
    public List<Column> getFullTableColumns(final String schema, final String table)
        throws SQLException
    {
    	final List<Column> columns = new ArrayList<Column>();
        final DatabaseMetaData dmd = getConnection().getMetaData();
        ResultSet rs = null;
        try {
            rs = dmd.getColumns(null,
                                correct(schema), correct(table),
                                null);
            while(rs.next()) {
            	final Column c = new Column(rs.getString(4).toUpperCase(),rs.getInt(5),rs.getLong(7),false);
                columns.add(c);
            }
            return columns;
        } finally {
            if(rs != null) {
                rs.close();
            }
        }
    }
    /**
     * Ustawia parametry ostaniego zapytania 
     * @param lst lst
     * @param let let
     * @param lsql lsql
     */
    public void setLast(final long lst, final long let, final String lsql){
    	this.LAST_START_TIME = lst;
    	this.LAST_EXECUTION_TIME = let;
    	this.LAST_QUERY = lsql;
    }
    /**
     * Pobiera czas rozpocz�cie ostatniego zapytania z tego po��czenia
     * @return long
     */
    public long getLastStartTime(){
    	return LAST_START_TIME;
    }
    /**
     * Pobiera czas ostatniego zapytania z tego po��czenia
     * @return long
     */
    public long getLastExecutionTime(){
    	return LAST_EXECUTION_TIME;
    }
    /**
     * Zwraca ostanie zapytanie z tego po��czenia
     * @return String
     */
    public String getLastQuery(){
    	return LAST_QUERY;
    }

    /**
     * Pobiera DatabaseMetaData
     * @return DatabaseMetaData
     * @throws SQLException
     */
    public DatabaseMetaData getMetaData()throws SQLException
    {
        return connection.getMetaData();
    }
    /**
     * Pobiera kontener
     * @return Container
     */
    public Container getContainer(){
    	return values;
    }
    /**
     * Sprawdza czy istnieje schemat o podanej nazwie
     * @param schema schema
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsSchema(String)
     * @see parasoft.centrap.connection.OracleConnection#existsSchema(String)
     */
    public abstract boolean existsSchema(String schema) throws SQLException;

    /**
     * Tworzy tabele z podanymi polami
     * @param table table
     * @param fields fields 
     */

    public void createTable(final String table, final String fields) throws SQLException
    {
        executeUpdate("CREATE TABLE " + table + " " + fields);
    }


    /**
     * Usuwa tabele z bazy danych
     * @param table table
     * @see parasoft.centrap.connection.PostgreSQLConnection#dropTable(String)
     * @see parasoft.centrap.connection.OracleConnection#dropTable(String)
     */
    public abstract void dropTable(String table) throws SQLException;

    /**
     * Sprawdza czy istnieje tabela
     * @param table table
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsTable(String)
     * @see parasoft.centrap.connection.OracleConnection#existsTable(String)
     */
    public abstract boolean existsTable(String table) throws SQLException;

    /**
     * Sprawdza czy istnieje tabela
     * @param schema schema
     * @param table table
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsTable(String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsTable(String, String)
     */
    public abstract boolean existsTable(String schema, String table) throws SQLException;

    /**
     * Pobiera kolumny z tabeli
     * @param table table
     * @return List<String>
     * @see parasoft.centrap.connection.PostgreSQLConnection#getTableColumns(String)
     * @see parasoft.centrap.connection.OracleConnection#getTableColumns(String)
     */
    public abstract List<String> getTableColumns(String table) throws SQLException;

    /**
     * Pobiera kolumny z tabeli
     * @param schema schema
     * @param table table
     * @return List<String>
     * @see parasoft.centrap.connection.PostgreSQLConnection#getTableColumns(String, String)
     * @see parasoft.centrap.connection.OracleConnection#getTableColumns(String, String)
     */
    public abstract List<String> getTableColumns(String schema, String table) throws SQLException;

    /**
     * Sprawdza czy istnieje kolumna w tabeli
     * @param table table
     * @param column column
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsTableColumn(String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsTableColumn(String, String)
     */
    public abstract boolean existsTableColumn(String table, String column) throws SQLException;

    /**
     * Sprawdza czy istnieje kolumna w tabeli
     * @param schema schema
     * @param table table
     * @param column column
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsTableColumn(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsTableColumn(String, String, String)
     */
    public abstract boolean existsTableColumn(String schema, String table, String column) throws
        SQLException;

    /**
     * Tworzy widok z podanych parametr�w
     * @param name name
     * @param query query
     */
    public void createView(final String name, final String query) throws java.sql.SQLException
    {
        executeUpdate("CREATE OR REPLACE VIEW " + name + " AS " + query );
    }

    /**
     * Usuwa widok o podanej nazwie
     * @param name name
     */
    public void dropView(final String name) throws java.sql.SQLException
    {
        executeUpdate("DROP VIEW " + name + " CASCADE");
    }

    /**
     * Sprawdza czy istnieje widok o podanych parametrach
     * @param name name
     * @return boolean
     */
    public boolean existsView(final String name) throws java.sql.SQLException
    {
        final DatabaseMetaData dmd = getConnection().getMetaData();
        ResultSet rs = null;
        final String[] aTypes = { "VIEW" };
		final String schema = "";
        try {
            rs = dmd.getTables(null,
            		correct(schema), correct(name),
                               aTypes);
            return rs.next();
        } finally {
            if(rs != null) {
                rs.close();
            }
        }
    }

    /**
     * Sprawdza czy istnieje widok o podanych parametrach
     * @param schema schema
     * @param name name
     * @return boolean
     */
    public boolean existsView(final String schema, final String name) throws java.sql.SQLException
    {
        final DatabaseMetaData dmd = getConnection().getMetaData();
        ResultSet rs = null;
        final String[] aTypes = { "VIEW" };
        try {
            rs = dmd.getTables(null,
                               correct(schema), correct(name),
                               aTypes);
            return rs.next();
        } finally {
            if(rs != null) {
                rs.close();
            }
        }
    }

    /**
     * Tworzy wyzwalacz o podanych parametrach
     * @param name name
     * @param tableName tableName
     * @param functName functName 
     * @see parasoft.centrap.connection.PostgreSQLConnection#createTrigger(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#createTrigger(String, String, String)
     */
    public abstract void createTrigger(String name, String tableName, String functName) throws
        SQLException;

    /**
     * Sprawdza czy istnieje wyzwalacz o podanych parametrach
     * @param triggerName triggerName
     * @param schema schema
     * @param tableName tableName
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsTrigger(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsTrigger(String, String, String)
     */
    public abstract boolean existsTrigger(String triggerName, String schema, String tableName) throws
        SQLException;

    /**
     * Tworzy funkcj� o podanych parametrach
     * @param name name
     * @param functBody functBody
     * @see parasoft.centrap.connection.PostgreSQLConnection#createFunction(String, String)
     * @see parasoft.centrap.connection.OracleConnection#createFunction(String, String)
     */
    public abstract void createFunction(String name, String functBody) throws SQLException;

    /**
     * Usuwa funkcj� o podanej nazwie
     * @param name name
     * @see parasoft.centrap.connection.PostgreSQLConnection#dropFunction(String)
     * @see parasoft.centrap.connection.OracleConnection#dropFunction(String)
     */
    public abstract void dropFunction(String name) throws SQLException;

    /**
     * Sprawdza czy istnieje funckja o podanej nazwie
     * @param name name
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsFunction(String)
     * @see parasoft.centrap.connection.OracleConnection#existsFunction(String)
     */
    public abstract boolean existsFunction(String name) throws SQLException;

    /**
     * Sprawdza czy istnieje funckja o podanych parametrach
     * @param name name
     * @param functbody functbody
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsFunction(String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsFunction(String, String)
     */
    public abstract boolean existsFunction(String name, String functbody) throws SQLException;

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za 
     * @see parasoft.centrap.connection.PostgreSQLConnection#createSequence(String)
     * @see parasoft.centrap.connection.OracleConnection#createSequence(String)
     */
    public abstract void createSequence(String key) throws SQLException;

    /**
     * Tworzy sekwencj� z podanych parametr�w
     * @param key key
     * @param start start
     * @see parasoft.centrap.connection.PostgreSQLConnection#createSequence(String, long)
     * @see parasoft.centrap.connection.OracleConnection#createSequence(String, long)
     */
    public abstract void createSequence(String key, long start) throws SQLException;

    /**
     * Usuwa sekwencj� o podanej nazwie
     * @param key key
     * @see parasoft.centrap.connection.PostgreSQLConnection#dropSequence(String)
     * @see parasoft.centrap.connection.OracleConnection#dropSequence(String)
     */
    public abstract void dropSequence(String key) throws SQLException;

    /**
     * Usuwa kolumn� z podanych parametr�w
     * @param schema schema
     * @param table table
     * @param field field
     */
    public void dropColumn(final String schema, final String table,final String field) throws SQLException{
    	executeUpdate("ALTER TABLE " + schema + "." + table + " DROP COLUMN " + field);
    }

    /**
     * Sprawdza czy istnieje sekwencja o podanej nazwie
     * @param key
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsSequence(String)
     * @see parasoft.centrap.connection.OracleConnection#existsSequence(String)
     */
    public abstract boolean existsSequence(String key) throws SQLException;

    /**
     * Sprawdza czy istnieje sekwencja o podanej nazwie
     * @param schema schema
     * @param key key
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsSequence(String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsSequence(String, String)
     */
    public abstract boolean existsSequence(String schema, String key) throws SQLException;

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za pobieranie aktualnej warto�ci sekwencji
     * @param key key
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#sCurrVal(String)
     * @see parasoft.centrap.connection.OracleConnection#sCurrVal(String)
     */
    public abstract String sCurrVal(String key);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za pobieranie nast�pnej warto�ci sekwencji
     * @param key key
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#sNextVal(String)
     * @see parasoft.centrap.connection.OracleConnection#sNextVal(String)
     */
    public abstract String sNextVal(String key);

    /**
     * Tworzy zapytania, kt�re umo�liwia dost�p do tabeli tymczasowej
     * @param column column 
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#sTempSelect(String)
     * @see parasoft.centrap.connection.OracleConnection#sTempSelect(String)
     */
    public abstract String sTempSelect(String column);

    /**
     * Pobiera aktualny numer z sekwencji o nazwie key
     * @param key key
     * @return long
     * @see parasoft.centrap.connection.PostgreSQLConnection#currentId(String)
     * @see parasoft.centrap.connection.OracleConnection#currentId(String)
     */
    public abstract long currentId(String key) throws SQLException;

    /**
     * Kobiera kolejny numer sekwencji o nazwie key
     * @param key key
     * @return long
     * @see parasoft.centrap.connection.PostgreSQLConnection#nextId(String)
     * @see parasoft.centrap.connection.OracleConnection#nextId(String)
     */
    public abstract long nextId(String key) throws SQLException;

    /**
     * Tworzy indeks z podanych parametr�w
     * @param schema schema
     * @param table table
     * @param column column
     * @see parasoft.centrap.connection.PostgreSQLConnection#createIndex(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#createIndex(String, String, String)
     */
    public abstract void createIndex(String schema, String table, String column) throws SQLException;

    /**
     * Usuwa indeks o podanych parametrach
     * @param schema schema
     * @param table table
     * @param column column
     * @see parasoft.centrap.connection.PostgreSQLConnection#dropIndex(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#dropIndex(String, String, String)
     */
    public abstract void dropIndex(String schema, String table, String column) throws SQLException;

    /**
     * Sprawdza czy istnieje indeks o podanej nazwie
     * @param table table
     * @param column column
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsIndex(String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsIndex(String, String)
     */
    public abstract boolean existsIndex(String table, String column) throws SQLException;

    /**
     * Sprawdza czy istnieje indeks o podanej nazwie
     * @param schema schema
     * @param table table
     * @param column column
     * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsIndex(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#existsIndex(String, String, String)
     */
    public abstract boolean existsIndex(String schema, String table, String column) throws
        SQLException;

    /**
     * Tworzy indeks na podstawie podanych parametr�w
     * @param index_name index_name
     * @param table table
     * @param columns columns
     * @see parasoft.centrap.connection.PostgreSQLConnection#createIndex(String, String, List)
     * @see parasoft.centrap.connection.OracleConnection#createIndex(String, String, List)
     */
    public abstract void createIndex(String index_name, String table, List<String> columns) throws
        SQLException;

    /**
     * Usuwa indeks o podanej nazwie
     * @param index_name index_name 
     * @see parasoft.centrap.connection.PostgreSQLConnection#dropIndex(String)
     * @see parasoft.centrap.connection.OracleConnection#dropIndex(String)
     */
    public abstract void dropIndex(String index_name) throws SQLException;

    /**
     * Sprawdza czy istnieje indeks o podanej nazwie
     * @param index_name index_name
     * @return boolean 
     * @see parasoft.centrap.connection.PostgreSQLConnection#existsIndex(String)
     * @see parasoft.centrap.connection.OracleConnection#existsIndex(String)
     */
    public abstract boolean existsIndex(String index_name) throws SQLException;

    /**
     * Zwraca informacj�, czy zaptanie mo�e zawiera� klauzul� OUTER JOIN
	 * @return boolean
     * @see parasoft.centrap.connection.PostgreSQLConnection#isOuterJoin()
     * @see parasoft.centrap.connection.OracleConnection#isOuterJoin()
     */
    public abstract boolean isOuterJoin();

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za ��czenie dw�ch tabel|podzapyta�
     * @param column column
     * @param condition condition
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#leftJoin(String, String)
     * @see parasoft.centrap.connection.OracleConnection#leftJoin(String, String)
     */
    public abstract String leftJoin(String column, String condition);

    /**
     * Obudowuje zapytanie o limit do pierwszego pierwsza
     * @param query zapytanie do limitu
     * @return zapytanie z klauzul� limituj�c� wiersze do pierwszego
     * @see parasoft.centrap.connection.PostgreSQLConnection#appendQueryLimit(String)
     * @see parasoft.centrap.connection.OracleConnection#appendQueryLimit(String)
     */
    public abstract String appendQueryLimit(String query);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za tworzenie instrukcji case|switch
     * @param expression nazwa kolumny
     * @param values warunki
     * @param results warto�ci dla warunk�w
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#decodeQuery(String, List, List)
     * @see parasoft.centrap.connection.OracleConnection#decodeQuery(String, List, List)
     */
    public abstract String decodeQuery(String expression, List<String> values, List<String> results);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za tworzenie instrukcji case|switch
     * @param expression nazwa kolumny
     * @param values warunki
     * @param results warto�ci dla warunk�w
     * @param resround czy zaokr�gla�
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#decodeQuery(String, List, List, boolean)
     * @see parasoft.centrap.connection.OracleConnection#decodeQuery(String, List, List, boolean)
     */
    public abstract String decodeQuery(String expression, List<String> values, List<String> results,
                                       boolean resround);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na date
     * @param column column
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#dateTrunc(String)
     * @see parasoft.centrap.connection.OracleConnection#dateTrunc(String)
     */
    public abstract String dateTrunc(String column);

	/**
	 * Tworzy fragment zapytania, kt�ry odpowiada za wyci�ganie podanej cz�ci
	 * timestampa (znacznika czasowego) - godziny, minuty itp.
	 *
	 * @param datetimePart Cz�� timestampa; np. hour, minute, year, month.
	 * @param column       Timestamp (znacznik czasowy).
	 * @return             Liczba reprezentuj�ca dan� cz�� timestampa,
	 *                     np. 13 dla czasu 13:25.
	 */
	public abstract String datetimeExtract(String datetimePart, String column);
	
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za wyci�ganie liczby sekund w pola daty
     * @param column column
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#secOfDay(String)
     * @see parasoft.centrap.connection.OracleConnection#secOfDay(String)
     */
    public abstract String secOfDay(String column);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na typ numeric
     * @param column column
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#numericCast(String)
     * @see parasoft.centrap.connection.OracleConnection#numericCast(String)
     */
    public abstract String numericCast(String column);
    
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na typ DATE
     * @param column column
     * @return String
     */
    public String dateCast(final String column)
    {
        return "cast(" + column + " as DATE)";
    }
    /**
     * Zwraca fragment zapytania reprezentuj�cy aktualny timestamp
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#currentTimestamp()
     * @see parasoft.centrap.connection.OracleConnection#currentTimestamp()
     */
    public abstract String currentTimestamp();
    /**
     * Zwraca fragment zapytania reprezentuj�cy aktualn� dat�
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#currentDate()
     * @see parasoft.centrap.connection.OracleConnection#currentDate()
     */
    public abstract String currentDate();
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na typ TIMESTAMP
     * @param column column
     * @return String
     */
    public String timestampCast(final String column)
    {
        return "cast(" + column + " as TIMESTAMP)";
    }
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na typ varchar
     * @param column column
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#varcharCast(String)
     * @see parasoft.centrap.connection.OracleConnection#varcharCast(String)
     */
    public abstract String varcharCast(String column);
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersj� pola kolumny column na typ varchar na podany format
     * @see <a href="http://developer.postgresql.org/pgdocs/postgres/functions-formatting.html"/>Postgres format</a>
     * @see <a href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#SQLRF00210"/>Oracle format</a>
     * @param column column
     * @param format format
     * @return String
     */
    public String varcharCast(final String column, final String format) {
    	return "to_char("+column+",'"+format+"')";
    }
    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za konwersje wyra�enie na typ varchar
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#varcharCast()
     * @see parasoft.centrap.connection.OracleConnection#varcharCast()
     */
    public abstract String varcharCast();

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za podnoszenie number do pot�gi exponent
     * @param number number
     * @param exponent exponent
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#power(String, String)
     * @see parasoft.centrap.connection.OracleConnection#power(String, String)
     */
    public abstract String power(String number, String exponent);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za zaokr�glenie liczby number do precyzji precision
     * @param number number
     * @param precision precision
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#round(String, int)
     * @see parasoft.centrap.connection.OracleConnection#round(String, int)
     */
    public abstract String round(String number, int precision);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za wykonanie operacji arg1 & arg2
     * @param arg1 arg1
     * @param arg2 arg2
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#bitand(String, String)
     * @see parasoft.centrap.connection.OracleConnection#bitand(String, String)
     */
    public abstract String bitand(String arg1, String arg2);

    /**
     * Tworzy fragment zapytania, kt�ry odpowiada za ��czenie dw�ch �a�cuch�w
     * @param str1 str1
     * @param str2 str2
     * @return String
     * @see parasoft.centrap.connection.PostgreSQLConnection#concat(String, String)
     * @see parasoft.centrap.connection.OracleConnection#concat(String, String)
     */
    public abstract String concat(String str1, String str2);

    /**
     * Pobiera list� schemat�w
     * @return List<String>
     * @see parasoft.centrap.connection.PostgreSQLConnection#getSchemas()
     * @see parasoft.centrap.connection.OracleConnection#getSchemas()
     */
    public abstract List<String> getSchemas() throws SQLException;

    /**
     * Pobiera list� tabel
     * @param schema schema
     * @return lista tabel
     * @throws SQLException
     */
    public List<String> getTables(final String schema) throws SQLException
    {
        final DatabaseMetaData dmd = getConnection().getMetaData();
        ResultSet rs = null;
        final List<String> list = new ArrayList<String>();
        final String[] aTypes = { "TABLE" };
        try {
            rs = dmd.getTables(null,
            		correct(schema), null,
                               aTypes);
            while(rs.next()) {
            	list.add(rs.getString(3));
            }
            return list;
        } finally {
            if(rs != null) {
                rs.close();
            }
        }
    }
    /**
     * Pobiera list� obiekt�w bazy danych
     * @param schema schema
     * @return lista tabel
     * @throws SQLException
     */
    public List<String> getTables(final String schema, final List<String> types) throws SQLException
    {
        final DatabaseMetaData dmd = getConnection().getMetaData();
        ResultSet rs = null;
        final List<String> list = new ArrayList<String>();
        final String[] aTypes = { "TABLE" };
        types.toArray(aTypes);
        try {
            rs = dmd.getTables(null,
            		correct(schema), null,
                               aTypes);
            while(rs.next()) {
            	list.add(rs.getString(3));
            }
            return list;
        } finally {
            if(rs != null) {
                rs.close();
            }
        }
    }

    /**
     * Pobiera list� kolumn
     * @param schema schemat
     * @param table tabela
     * @return list� kolumn
     * @throws SQLException
     */
    public List<Column> getColumns(final String schema, final String table)
	throws SQLException
	{
	    final DatabaseMetaData dmd = getConnection().getMetaData();
	    ResultSet rs = null;
	    final List<Column> columns = new ArrayList<Column>();
	    try {
	        rs = dmd.getColumns(null,
	        		correct(schema), correct(table),
	                            null);
	        while(rs.next()) {
            	if(rs.getString(4) != null) {
	            	final String columnName = rs.getString(4);
	            	final int sqlType = Integer.parseInt(rs.getString(5));
	            	final long length = Long.parseLong(rs.getString(7));
	            	boolean isNotNull = false;

	            	if(rs.getString(11).equals("0")) {
	            		isNotNull = true;
	            	}

	            	String defaultValue = null;

	            	if(rs.getLong(13) != 0) {
	            		defaultValue = rs.getString(13).trim();
	            	}

	            	Column column = null;
	            	if(defaultValue != null) {
	            		column = new Column(columnName, sqlType, length, isNotNull, defaultValue);
	            	}
	            	else {
	            		column = new Column(columnName, sqlType, length, isNotNull);
	            	}
	                columns.add(column);
	            }
	        }
	        return columns;
	    } finally {
	        if(rs != null) {
	            rs.close();
	        }
	    }
	}

    /**
     * Pobiera klucz g��wny
     * @param schema schema
     * @param table table
     * @return String
     */
    public String getPrimaryKey(final String schema, final String table)
	throws SQLException
	{
		 final DatabaseMetaData dmd = getConnection().getMetaData();
		 ResultSet rs = null;
		 try {
			 rs = dmd.getPrimaryKeys(null, correct(schema), correct(table));
			 while(rs.next()) {
				 if(rs.getString(4) != null) {
		            return rs.getString(4);
		        }
		    }
		    return null;
		} finally {
		    if(rs != null) {
		    	rs.close();
		    }
		}
	}

    /**
     * Tworzy schemat
     * @param schemaName schemaName
     * @see parasoft.centrap.connection.PostgreSQLConnection#createSchema(String)
     * @see parasoft.centrap.connection.OracleConnection#createSchema(String)
     */
    public abstract void createSchema(String schemaName) throws SQLException;

    /**
     * Pobiera indeks
     * @param schema schema
     * @param table table
     * @return List
     * @see parasoft.centrap.connection.PostgreSQLConnection#getIndexs(String, String)
     * @see parasoft.centrap.connection.OracleConnection#getIndexs(String, String)
     */
    public abstract List<Index> getIndexs(String schema, String table) throws java.sql.SQLException;

    /**
     * Tworzy indeks
     * @param index_name index_name
     * @param table table
     * @param columns columns
     * @param unique unique
     * @see parasoft.centrap.connection.PostgreSQLConnection#createIndex(String, String, List, boolean)
     * @see parasoft.centrap.connection.OracleConnection#createIndex(String, String, List, boolean)
     */
    public abstract void createIndex(String index_name, String table, List<String> columns, boolean unique) throws java.sql.SQLException;
    /**
     * Zmienia typ kolumny
     * @param tableName tableName
     * @param columnName columnName
     * @param newType newType
     * @see parasoft.centrap.connection.PostgreSQLConnection#alterColumnType(String, String, String)
     * @see parasoft.centrap.connection.OracleConnection#alterColumnType(String, String, String)
     */
    public abstract void alterColumnType(String tableName, String columnName, String newType) throws java.sql.SQLException;

    /**
     * @param param
     * @return String
     */
    public String correct(final String param){
    	return param;
    }    
}
